﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AbstraX;
using System.ComponentModel.DataAnnotations;
using AbstraX.ServerInterfaces;
using System.ServiceModel.DomainServices.Server;
using System.Runtime.Serialization;
using System.Net;
using System.IO;
using Reflection = System.Reflection;
using System.Diagnostics;
using AbstraX.XPathBuilder;
using System.GAC;
using System.Reflection;
using System.Collections;
using AbstraX.Templates;
using AbstraX.AssemblyInterfaces;
using System.Configuration;
using AbstraX.Contracts;
using MvvmTreeView;

namespace AssemblyProvider.Web.Entities
{
    [DataContract, NodeImage("AssemblyProvider.Web.Images.AssembliesRoot.png"), DebuggerDisplay("{ DebugInfo }"), ClientCodeGeneration(typeof(AbstraXClientInterfaceGenerator)), KnownType(typeof(Facet))]
    public class AssembliesRoot : IRoot, IAssembliesRoot 
    {
        private string queryWhereProperty;
        private object queryWhereValue;
        private AssemblyCache assemblyCache = new AssemblyCache();
        private List<string> safeAssemblies;
        private float childOrdinal;

        public AssembliesRoot()
        {
            safeAssemblies = (List<string>) ConfigurationManager.GetSection("SafeAssembliesSection/SafeAssemblies");
        }

        public AssembliesRoot(List<string> assemblies)
        {
            safeAssemblies = assemblies;
        }

        [DataMember]
        public float ChildOrdinal
        {
            get 
            {
                return childOrdinal;
            }
        }

        [DataMember]
        public string DebugInfo
        {
            get 
            {
                return this.Name + ":" + ID;
            }
        }

        [DataMember, Key]
        public string ID
        {
            get
            {
                return this.MakeID("URL='" + this.URL + "'");
            }
        }

        [DataMember]
        public string FolderKeyPair { get; set; }

        private AssemblyName GetAssemblyName(IAssemblyName nameRef)
        {
            AssemblyName name = new AssemblyName();
            name.Name = AssemblyCache.GetName(nameRef);

            try
            {
                name.Version = AssemblyCache.GetVersion(nameRef);
            }
            catch
            {

            }

            name.CultureInfo = AssemblyCache.GetCulture(nameRef);
            name.SetPublicKeyToken(AssemblyCache.GetPublicKeyToken(nameRef));
            return name;
        }

        [DataMember, Association("AssembliesRoot_Assemblies", "ID", "ParentID"), ClientCodeGeneration(typeof(AbstraXClientInterfaceGenerator))]
        public List<Assembly> Assemblies
        {
            get
            {
                List<Assembly> assemblies = new List<Assembly>();

                foreach (var safeAssembly in safeAssemblies)
                {
                    var fileInfo = new FileInfo(safeAssembly);
                    var isFile = false;

                    Reflection.Assembly assembly = null;

                    try
                    {
                        if (fileInfo.Exists)
                        {
                            assembly = Reflection.Assembly.LoadFrom(safeAssembly);
                            isFile = true;
                        }
                        else
                        {
                            assembly = Reflection.Assembly.Load(safeAssembly);
                        }
                    }
                    catch (Exception e) { }

                    if (assembly != null)
                    {
                        if (isFile)
                        {
                            assemblies.Add(new Assembly(assembly, safeAssembly, this));
                        }
                        else
                        {
                            assemblies.Add(new Assembly(assembly, this));
                        }
                    }
                }

                return assemblies;
            }
        }

        [DataMember]
        public string URL
        {
            get 
            {
                return DNSHelper.MakeURL("AssembliesRoot");
            }
        }

        [DataMember]
        public ProviderType ProviderType
        {
            get 
            {
                return ProviderType.AssemblyMap;
            }
        }

        [DataMember]
        public IEnumerable<IElement> RootElements
        {
            get 
            {
                IQueryable<IElement> elements = null;

                if (queryWhereProperty == null)
                {
                    elements = this.Assemblies.AsQueryable().Cast<IElement>().OrderBy(e => e.Name);
                }
                else
                {
                    try
                    {
                        List<IElement> list;
                        var id = (string)queryWhereValue;

                        if (queryWhereProperty == "Assembly")
                        {
                            var assembly = Reflection.Assembly.Load(id);
                            list = new List<IElement> { new Assembly(assembly, this) };
                        }
                        else if (queryWhereProperty == "AssemblyFile")
                        {
                            var assembly = Reflection.Assembly.LoadFrom(id);
                            list = new List<IElement> { new Assembly(assembly, id, this) };
                        }
                        else
                        {
                            throw new Exception("Invalid query");
                        }

                        elements = list.AsQueryable<IElement>();
                    }
                    catch
                    {
                        return new List<IElement>().AsEnumerable();
                    }
                }

                return elements;
            }
        }
        
        [DataMember]
        public string ParentID
        {
            get 
            {
                return string.Empty;
            }
        }

        [DataMember]
        public string Name
        {
            get 
            {
                return "Assemblies";
            }
        }

        [DataMember]
        public string Description
        {
            get
            {
                return string.Empty;
            }
        }

        [DataMember]
        public string Documentation
        {
            get
            {
                return string.Empty;
            }
        }

        [DataMember]
        public string ImageURL
        {
            get
            {
                return string.Empty;
            }
        }

        [DataMember, Include, Association("Parent_BaseType", "ID", "ParentID"), ClientCodeGeneration(typeof(AbstraXClientInterfaceGenerator))]
        public BaseType DataType
        {
            get 
            {
                return null;
            }
        }

        [Invoke]
        public void Dispose()
        {
            
        }

        public IBase Parent
        {
            get 
            {
                return null;
            }
        }

        public void ExecuteWhere(string property, object value)
        {
            queryWhereProperty = property;
            queryWhereValue = value;
        }

        public void ExecuteWhere(System.Linq.Expressions.Expression expression)
        {
            throw new NotImplementedException();
        }

        public void ExecuteWhere(XPathAxisElement element)
        {
            var predicate = element.Predicates.First();

            queryWhereProperty = predicate.Left;
            queryWhereValue = predicate.Right;
        }

        public void ClearPredicates()
        {
            queryWhereProperty = null;
            queryWhereValue = null;
        }

        public void ExecuteGlobalWhere(XPathAxisElement element)
        {
        }

        [DataMember]
        public DefinitionKind Kind
        {
            get 
            {
                return DefinitionKind.NotApplicable;
            }
        }

        public string ParentFieldName
        {
            get 
            {
                return "parentID";
            }
        }

        [DataMember]
        public bool HasChildren
        {
            get 
            {
                List<Assembly> assemblies = new List<Assembly>();

                foreach (var safeAssembly in safeAssemblies)
                {
                    var fileInfo = new FileInfo(safeAssembly);

                    Reflection.Assembly assembly = null;

                    try
                    {
                        if (fileInfo.Exists)
                        {
                            assembly = Reflection.Assembly.LoadFrom(safeAssembly);
                        }
                        else
                        {
                            assembly = Reflection.Assembly.Load(safeAssembly);
                        }
                    }
                    catch (Exception e) { }

                    if (assembly != null)
                    {
                        return true;
                    }
                }

                return false;
            }
        }

        IEnumerable<IAssembly> IAssembliesRoot.Assemblies
        {
            get
            {
                foreach (var assembly in this.Assemblies)
                {
                    yield return assembly;
                }
            }
        }

        [DataMember, Include, Association("Parent_Facet", "ID", "ParentID")]
        public Facet[] Facets
        {
            get
            {
                return null;
            }
        }
    }
}
